﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using SNSpirit.Domain.Rss;
using SNSpirit.Domain.User;
using SNSpirit.Web.Client;

namespace SNSpirit.Service.Web.Rss
{
    [Export(typeof(IRssServiceConnector)), PartCreationPolicy(CreationPolicy.Shared)]
    public class RssServiceConnector : IRssServiceConnector
    {
        [ImportingConstructor]
        public RssServiceConnector(IWebClientManager webClientMgr)
        {
            this._webClientManager = webClientMgr;
            // add default one
            this.RegisterFeedFactory(string.Empty, new DefaultRssFeedFactory());
        }

        #region register

        public void RegisterFeedFactory(string urlPrefix, IRssFeedFactory factory)
        {
            if (urlPrefix == null)
                throw new ArgumentNullException("urlPrefix");
            if (factory == null)
                throw new ArgumentNullException("factory");
            lock (this)
            {
                if (this._factoryList.Where(p => p.Item1 == urlPrefix).Count() != 0)
                    throw new InvalidOperationException("Url prefix has already exists");
                this._factoryList.Add(new Tuple<string, IRssFeedFactory>(urlPrefix, factory));
            }
        }

        public void UnregisterFeedFactory(string urlPrefix)
        {
            if (urlPrefix == null)
                throw new ArgumentNullException("urlPrefix");
            lock (this)
            {
                var items = this._factoryList.Where(p => p.Item1 == urlPrefix);
                if (items.Count() != 0)
                    this._factoryList.Remove(items.First());
            }
        }

        #endregion

        public bool Update(RssFeed feed)
        {
            lock (this)
            {
                string uri = feed.UpdateUri.ToString();
                // try to match the longest prefix
                var lst = this._factoryList.OrderByDescending(p => p.Item1.Length);
                foreach (var item in lst)
                    if (uri.StartsWith(item.Item1))
                    {
                        // hit
                        var webClient = this._webClientManager.GetWebClient(feed.UpdateUri);
                        var content = webClient.DownloadString(feed.UpdateUri);
                        return item.Item2.BuildRssFeed(feed, content);
                    }
                // not found
                // this should never happen
                throw new InvalidOperationException("Cannot find connector to handle this rss request");
            }
        }

        #region private

        private readonly List<Tuple<string, IRssFeedFactory>> _factoryList = new List<Tuple<string, IRssFeedFactory>>();

        private IWebClientManager _webClientManager;

        #endregion
    }
}
